﻿using PLCSharp.CoreModel.Common;
using PLCSharp.CoreModel.Prism;
using PLCSharp.CoreModel.Tools;
using PLCSharp.Views.Connects;
using PLCSharp.Views.GlobalVariables;
using PLCSharp.Views.Homepage;
using PLCSharp.Views.ModeState;
using PLCSharp.Views.MotionController;
using PLCSharp.Views.Recipe;
using PLCSharp.Views.Vision;
using PLCSharp.Views.Vision.Camera;
using PLCSharp.Views.Workflows;
using Prism.Commands;
using Prism.Dialogs;
using Prism.Events;
using Prism.Ioc;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Windows.Media;


namespace PLCSharp.Models
{
    [Model]
    public class GlobalModel : ModelBase
    {
        public GlobalModel(IContainerExtension container, IEventAggregator ea, IDialogService dialogService) : base(container, ea, dialogService)
        {
            NatashaManagement
                 //获取链式构造器
                 .GetInitializer()
                 //使用引用程序集中的命名空间
                 .WithMemoryUsing()
                 //使用内存中的元数据
                 .WithMemoryReference()
                 //注册域构造器
                 .Preheating<NatashaDomainCreator>();
            foreach (var item in _DatasContext.Recipes)
            {
                var recipe = item.DeepCopy();
                Recipes.Add(recipe);

            }


            if (Recipes.Count == 0)
            {
                var recipe = container.Resolve<Recipe>();
                recipe.Name = "First";
                recipe.Comment = "";
                recipe.Prompt = "默认配方";
                recipe.Current = true;
                Recipes.Add(recipe);
                RecipeSelected = recipe;
                ExecuteRecipeManage("Save");
                CurrentRecipe = recipe;
            }
            else
            {
                CurrentRecipe = Recipes.Where(r => r.Current == true).FirstOrDefault();

                if (CurrentRecipe == null)
                {
                    CurrentRecipe = Recipes.FirstOrDefault();
                    CurrentRecipe.Current = true;
                    RecipeSelected = CurrentRecipe;
                    ExecuteRecipeManage("Save");
                }
            }
            VariablesModel = container.Resolve<VariablesModel>();
            VariablesModel.Init(this);
            Variables = VariablesModel.Variables;
            Connects = container.Resolve<ConnectsModel>();
            Connects.Init(this);
            ControllersModel = container.Resolve<ControllersModel>();
            ControllersModel.Init(this);
            WorkflowsModel = container.Resolve<WorkflowsModel>();
            VisionsModel = container.Resolve<VisionsModel>();

            bkgWorker = new BackgroundWorker { WorkerSupportsCancellation = true };
            bkgWorker.DoWork += BackgroundWork;
            bkgWorker.RunWorkerAsync();

            //注册发送给errLog的消息
            ea.GetEvent<MessageEvent>().Subscribe(
                ErrMessageReceived,
                ThreadOption.UIThread,
                false,
                (filter) => filter.Target.Contains("errLog"));

            //注册配方变更
            ea.GetEvent<MessageEvent>().Subscribe(
                RecipeChanged,
                ThreadOption.UIThread,
                false,
                (filter) => filter.Target.Contains("RecipeChanged"));

            ShowLog();
        }

        #region 全局变量
        public ObservableCollection<Variable> Variables { get; set; }

        public Variable GetVariable(string name)
        {
            var variable = Variables.FirstOrDefault(v => v.Name == name)
              ?? throw new Exception("全局变量未配置!");
            return variable;
        }

        #endregion
        #region 硬件
        public ConnectsModel Connects { get; set; }
        public ControllersModel ControllersModel { get; set; }

        public VariablesModel VariablesModel { get; set; }
        public Connect GetConnect(string name)
        {
            var connect = Connects.Connects.FirstOrDefault(c => c.Name == name)
                                ?? throw new Exception("网络未配置!");
            if (connect.Connected == false)
            {
                throw new Exception("网络未连接!");
            }
            return connect;
        }
        public CameraBase GetCamera(string name)
        {
            return VisionsModel.Cameras.FirstOrDefault(c => c.Name == name)
                 ?? throw new Exception("相机未配置!");
        }

        public VisionFunction GetVisionFunction(string name)
        {
            return VisionsModel.VisionFunctions.FirstOrDefault(v => v.Name == name)
                 ?? throw new Exception("视觉功能未配置!");
        }
        public ImageData GetImageData(string name)
        {
            var imageData = VisionsModel.ImageDatas.FirstOrDefault(v => v.Name == name)
                 ?? throw new Exception("全局图像未配置!");
            if (imageData.Mat == null) throw new Exception("全局图像未赋值!");
            return imageData;
        }


        #endregion
        #region 任务
        public WorkflowsModel WorkflowsModel { get; set; }
        public VisionsModel VisionsModel { get; set; }
        public Workflow GetTask(string name)
        {
            return WorkflowsModel.Workflows.FirstOrDefault(t => t.Name == name);
        }
        #endregion
        #region 日志
        private ObservableCollection<ErrorLog> _ErrorLogs = [];

        public ObservableCollection<ErrorLog> ErrorLogs
        {
            get { return _ErrorLogs; }
            set { SetProperty(ref _ErrorLogs, value); }
        }
        private TitleState _CurrentState = new();
        /// <summary>
        /// 
        /// </summary>
        public TitleState TitleState
        {
            get { return _CurrentState; }
            set { SetProperty(ref _CurrentState, value); }
        }

        public void AddErrorLog(Message message)
        {
            if (TitleState.Info == message.Content)
            {
                TitleState.Background = Brushes.Red;
                return; //避免重复记录相同的错误
            }
            var newLog = new ErrorLog(message.Content);
            TitleState.Info = message.Content;
            TitleState.Background = Brushes.Red;
            _DatasContext.ErrorLogs.Add(newLog);
            ShowLog();

        }
        private readonly object loglock = new();
        private void ShowLog()
        {
            lock (loglock)
            {


                var showLog = _DatasContext.ErrorLogs.OrderByDescending(l => l.Time).Take(30).Where(e => e.Time.AddDays(1) >= DateTime.Now).ToList();

                foreach (var item in showLog)
                {
                    if (ErrorLogs.Contains(item))
                    {
                        continue;
                    }
                    ErrorLogs.Add(item);
                }

                var confirmedLog = ErrorLogs.Where(e => e.IsConfirm).ToList();

                //清理已确认的日志  
                foreach (var item in confirmedLog)
                {
                    ErrorLogs.Remove(item);
                }
            }
        }
        public void SendInfo(string message)
        {
            TitleState.Info = message;
            TitleState.Background = Brushes.Lime;
        }
        public void SendInfo(string message, Brush brush)
        {
            TitleState.Info = message;
            TitleState.Background = brush;
        }

        public void SendWarning(string message)
        {
            TitleState.Info = message;
            TitleState.Background = Brushes.Gold;
        }

        public void ErrorLogDialog(Message message)
        {
            _dialogService.Show("AlertDialog", new DialogParameters($"message={message.Content}"), r =>
            {
                if (r.Result == ButtonResult.Yes)
                {
                    //确认
                    var err = ErrorLogs.FirstOrDefault(e => e.Message == message.Content);
                    if (err != null)
                    {
                        err.IsConfirm = true;
                    }
                }
                else if (r.Result == ButtonResult.No)
                {
                    //取消
                }
            });
        }
        private void ErrMessageReceived(Message message)
        {
            switch (message.Type)
            {
                case ErrType.Record:

                    AddErrorLog(message);
                    break;

                case ErrType.ShowDialog:
                    ErrorLogDialog(message);
                    break;
                case ErrType.ShowDialogAndRecord:
                    AddErrorLog(message);
                    ErrorLogDialog(message);

                    break;
                default:
                    break;
            }

        }
        #endregion
        #region 模式与状态
        private ModeState _ModeState = new();
        public ModeState ModeState
        {
            get { return _ModeState; }
            set { SetProperty(ref _ModeState, value); }
        }

        private readonly BackgroundWorker bkgWorker;

        private void BackgroundWork(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;

            while (!worker.CancellationPending)
            {
                try
                {
                    if (ModeState.Sc.Reset)
                    {
                        TitleState.Background = Brushes.Gray;
                    }
                    ModeState.Run();


                }
                catch (Exception ex)
                {
                    SendErr(ex.Message, ErrType.Record);
                    goto sleep;
                }

            sleep:

                Thread.Sleep(1);
            }
        }
        #endregion
        #region 配方


        private Recipe _CurrentRecipe;
        /// <summary>
        /// 
        /// </summary>
        public Recipe CurrentRecipe
        {
            get { return _CurrentRecipe; }
            set
            {
                SetProperty(ref _CurrentRecipe, value);

                _DatasContext.CurrentRecipe = value;
            }
        }
        private Recipe _RecipeSelected;
        /// <summary>
        /// Comment
        /// </summary>
        public Recipe RecipeSelected
        {
            get { return _RecipeSelected; }
            set { SetProperty(ref _RecipeSelected, value); }
        }

        private ObservableCollection<Recipe> _Recipes = [];
        /// <summary>
        /// Comment
        /// </summary>
        public ObservableCollection<Recipe> Recipes
        {
            get { return _Recipes; }
            set { SetProperty(ref _Recipes, value); }
        }

        private DelegateCommand<string> _RecipeManage;
        public DelegateCommand<string> RecipeManage =>
            _RecipeManage ??= new DelegateCommand<string>(ExecuteRecipeManage);

        void ExecuteRecipeManage(string cmd)
        {
            if (ModeState.State.Execute)
            {

                SendErr($"无法在运行状态操作配方，请先停止", ErrType.ShowDialog);
                return;
            }
            switch (cmd)
            {
                case "New":
                    Recipes.Add(new Recipe());
                    break;

                case "Save":
                    var names = new List<string>();

                    foreach (var item in Recipes)
                    {
                        if (string.IsNullOrEmpty(item.Name))
                        {
                            SendErr($"保存失败，名称{item.Name}不合适！", ErrType.ShowDialog);
                            return;
                        }

                        if (names.Contains(item.Name))
                        {
                            SendErr($"保存失败，重复的名称{item.Name}！", ErrType.ShowDialog);
                            return;
                        }
                        else
                        {
                            names.Add(item.Name);
                        }
                    }


                    foreach (var item in Recipes)
                    {
                        if (!_DatasContext.Recipes.Any(h => h.ID == item.ID))
                        {
                            _DatasContext.Recipes.Add(item);

                        }
                        else
                        {
                            var camera = _DatasContext.Recipes.Where(c => c.Name == item.Name).FirstOrDefault();
                            camera.Comment = item.Comment;
                        }
                    }
                    RecipeSelected.Prompt = "";

                    break;

                case "Remove":
                    if (RecipeSelected != null)
                    {
                        if (RecipeSelected.ID != CurrentRecipe.ID)
                        {
                            {
                                var recipe = _DatasContext.Recipes.Where
                                     (r => r.ID == RecipeSelected.ID).FirstOrDefault();

                                if (recipe != null)
                                {
                                    _DatasContext.Recipes.Remove(recipe);
                                }

                                var name = RecipeSelected.Name;
                                Recipes.Remove(RecipeSelected);
                                SendErr($"已删除：{name}", ErrType.ShowDialog);
                                RecipeSelected = null;
                                _DatasContext.Save();
                            }
                        }
                        else
                        {
                            SendErr($"无法删除正在使用的配方，请切换到其它配方后再删除本配方!", ErrType.ShowDialog);
                        }
                    }
                    break;

                case "Current":
                    if (RecipeSelected != null)
                    {
                        foreach (var item in _DatasContext.Recipes)
                        {
                            item.Current = false;
                        }
                        var current = _DatasContext.Recipes.Where(r => r.ID == RecipeSelected.ID).FirstOrDefault();
                        if (current != null)
                        {
                            current.Current = true;
                            if (current != CurrentRecipe)
                            {
                                CurrentRecipe = current;

                                SendErr($"当前配方：{CurrentRecipe.Name}", ErrType.ShowDialog);
                                _EventAggregator.GetEvent<MessageEvent>().Publish(new()
                                {
                                    Target = "RecipeChanged"
                                });
                            }
                        }
                    }

                    break;
            }
        }

        /// <summary>
        /// 配方变更 
        /// </summary>
        /// <param name="message"></param>
        private void RecipeChanged(Message message)
        {
            //结束当前配方的任务

            foreach (var item in WorkflowsModel.Workflows)
            {
                try
                {
                    item.Stop();
                }
                catch (Exception)
                {

                }
            }
            // 重新加载画布配置和自定义控件

            CurrentCanvasConfig = _DatasContext.CanvasConfigs.Where(c => c.RecipeID == CurrentRecipe.ID).FirstOrDefault();

            if (CurrentCanvasConfig == null)
            {
                CurrentCanvasConfig = new CanvasConfig() { RecipeID = CurrentRecipe.ID };
                _DatasContext.Add(CurrentCanvasConfig);
            }

            var currRecipeCustomControls = _DatasContext.CustomControls.Where(c => c.RecipeID == CurrentRecipe.ID);
            CustomControls.Clear();
            foreach (var item in currRecipeCustomControls)
            {
                CustomControls.Add(item.DeepCopy());

            }
            var config = _DatasContext.CanvasConfigs.Where(c => c.RecipeID == CurrentRecipe.ID).FirstOrDefault();
            if (config != null)
            {
                CurrentCanvasConfig.Rows = config.Rows;
                CurrentCanvasConfig.Columns = config.Columns;
            }
            //重新加载主界面
            _EventAggregator.GetEvent<MessageEvent>().Publish(new()
            {
                Target = "UIReLoad"
            });
            //加载当前配方的变量列表
            Variables.Clear();
            var variables = _DatasContext.Variables.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in variables)
            {
                if (!item.RetainPersistent)
                    item.Value = item.DefaultValue;
                Variables.Add(item);
            }
            //加载当前配方的图像数据列表
            VisionsModel.ImageDatas.Clear();
            var currRecipeImageDatas = _DatasContext.ImageDatas.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in currRecipeImageDatas)
            {
                var itemcopy = item.DeepCopy();
                itemcopy.Prompt = "";
                VisionsModel.ImageDatas.Add(itemcopy);
            }

            //加载当前配方的视觉功能列表
            VisionsModel.VisionFunctions.Clear();
            var currRecipeVisionFunctions = _DatasContext.VisionFunctions.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in currRecipeVisionFunctions)
            {
                var itemcopy = item.DeepCopy();
                itemcopy.Prompt = "";
                itemcopy.VisionsModel = VisionsModel;
                itemcopy.ImageDatas = VisionsModel.ImageDatas;
                itemcopy.GlobalModel =  this;
                VisionsModel.VisionFunctions.Add(itemcopy);
            }
            //加载当前配方的点位列表
            ControllersModel.AxisPoints.Clear();
            var currRecipeAxisPoints = _DatasContext.AxisPoints.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in currRecipeAxisPoints)
            {
                var axisPoint = item.DeepCopy();
                ControllersModel.AxisPoints.Add(axisPoint);
                var axisX = ControllersModel.Axes.Where(a => a.Name == axisPoint.AxisXName).FirstOrDefault();
                if (axisX != null)
                    axisPoint.AxisX = axisX;
                var axisY = ControllersModel.Axes.Where(a => a.Name == axisPoint.AxisYName).FirstOrDefault();
                if (axisY != null)
                    axisPoint.AxisY = axisY;
                var axisZ = ControllersModel.Axes.Where(a => a.Name == axisPoint.AxisZName).FirstOrDefault();
                if (axisZ != null)
                    axisPoint.AxisZ = axisZ;
                var axisU = ControllersModel.Axes.Where(a => a.Name == axisPoint.AxisUName).FirstOrDefault();
                if (axisU != null)
                    axisPoint.AxisU = axisU;
            }
            //加载当前配方的插补列表

            ControllersModel.InterpolationGroups.Clear();
            var currRecipeInterpolationGroups = _DatasContext.InterpolationGroups.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in currRecipeInterpolationGroups)
            {
                var itemcopy = item.DeepCopy();
                ControllersModel.InterpolationGroups.Add(itemcopy);
                var axisX = ControllersModel.Axes.Where(a => a.Name == itemcopy.AxisXName).FirstOrDefault();
                if (axisX != null)
                    itemcopy.AxisX = axisX;
                var axisY = ControllersModel.Axes.Where(a => a.Name == itemcopy.AxisYName).FirstOrDefault();
                if (axisY != null)
                    itemcopy.AxisY = axisY;
            }
            //加载当前配方的任务列表
            WorkflowsModel.Workflows.Clear();
            var currRecipeWorkflows = _DatasContext.Workflows.Where(c => c.RecipeID == CurrentRecipe.ID);
            foreach (var item in currRecipeWorkflows)
            {
                var itemcopy = item.DeepCopy();
                itemcopy.Prompt = "";
                WorkflowsModel.Workflows.Add(itemcopy);
                itemcopy.Compile.Execute();
                itemcopy.Start(this);
            }

        }
        #endregion
        #region 界面
        private ObservableCollection<CustomControl> _CustomControls = [];
        /// <summary>
        /// Comment
        /// </summary>
        public ObservableCollection<CustomControl> CustomControls
        {
            get { return _CustomControls; }
            set { SetProperty(ref _CustomControls, value); }
        }

        public CustomControl GetCustomControl(string name)
        {

            return CustomControls.Where(c => c.Name == name).FirstOrDefault();
        }
        private CustomControl _SelectedCustControl;
        /// <summary>
        /// Comment
        /// </summary>
        public CustomControl SelectedCustomControl
        {
            get { return _SelectedCustControl; }
            set { SetProperty(ref _SelectedCustControl, value); }
        }

        private CanvasConfig _CurrentCanvasConfig;
        /// <summary>
        /// Comment
        /// </summary>
        public CanvasConfig CurrentCanvasConfig
        {
            get { return _CurrentCanvasConfig; }
            set { SetProperty(ref _CurrentCanvasConfig, value); }
        }

        private DelegateCommand _Apply;
        public DelegateCommand Apply =>
            _Apply ??= new DelegateCommand(ExecuteApply);

        void ExecuteApply()
        {

            var config = _DatasContext.CanvasConfigs.Where(c => c.RecipeID == CurrentRecipe.ID).FirstOrDefault();
            if (config != null)
            {
                config.Rows = CurrentCanvasConfig.Rows;
                config.Columns = CurrentCanvasConfig.Columns;
            }
            else
            {
                _DatasContext.CanvasConfigs.Add(CurrentCanvasConfig);

            }
            _EventAggregator.GetEvent<MessageEvent>().Publish(new()
            {
                Target = "UIReLoad"
            });

        }
        #endregion

    }
}